#!/usr/bin/env python
# Author: mingzhong.huang


import base64
import requests
from datetime import datetime, timedelta
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import json
from distutils.util import strtobool
from setting import config
from core.logger import logger
from sqlalchemy.orm import Session




class K8sPrometheus(object):
    def __init__(self):
        self.k8s_url = config.K8S_API
        self.k8s_token = config.K8S_TOKEN
        self.k8s_namespace = config.K8S_PROM_NAMESPACE
        self.k8s_header = {
           "Authorization":"Bearer "+self.k8s_token,
           "Content-Type": "application/json"
        }
        self.prometheus_url = config.K8S_PROM_URL
        requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


    def get_prometheus_rule(self, name):
        try:
            url = self.k8s_url + f"/apis/monitoring.coreos.com/v1/namespaces/{self.k8s_namespace}/prometheusrules/{name}"
            req = requests.get(url=url, headers=self.k8s_header, verify=False)
            if req.status_code != 200:
                logger.error(f"get prometheus rule:{name} failed => {req.text}")
                return False
            prometheus_rule = json.loads(req.text)
        except Exception as e:
            logger.error(f"get prometheus rule:{name} error => {e}")
            return False

        logger.info(f"get prometheus rule:{name} success")
        return prometheus_rule



    def create_prometheus_rule(self, prometheus_rule_data):
        try:
            data = json.dumps(prometheus_rule_data, ensure_ascii=False).encode()
            url = self.k8s_url + f"/apis/monitoring.coreos.com/v1/namespaces/{self.k8s_namespace}/prometheusrules/"
            req = requests.post(url=url, headers=self.k8s_header, verify=False, data=data)
            if req.status_code not in [200, 201]:
                logger.error(f"create prometheus rule:{prometheus_rule_data['metadata']['name']} failed => {req.text}")
                return False

        except Exception as e:
            logger.error(f"create prometheus rule:{prometheus_rule_data['metadata']['name']} error => {e}")
            return False

        logger.info(f"create prometheus rule:{prometheus_rule_data['metadata']['name']} success")
        return True



    def update_prometheus_rule(self, prometheus_rule_data):
        rule_name = prometheus_rule_data['metadata']['name']
        try:
            # 拿到现在k8s集群中的告警规则资源的版本号
            k8s_prometheus_rule = self.get_prometheus_rule(rule_name)
            if not k8s_prometheus_rule:
                logger.error(f"get prometheus rule:{rule_name} failed ")
                return False

            # 更新put请求的数据
            prometheus_rule_data["metadata"]["resourceVersion"] = k8s_prometheus_rule["metadata"]["resourceVersion"]
            data = json.dumps(prometheus_rule_data, ensure_ascii=False).encode()

            # 更新prometheus规则
            url = self.k8s_url + f"/apis/monitoring.coreos.com/v1/namespaces/{self.k8s_namespace}/prometheusrules/{rule_name}"
            req = requests.put(url=url, data=data, headers=self.k8s_header, verify=False)
            if req.status_code != 200:
                logger.error(f"update prometheus rule:{rule_name} failed => {req.text}")
                return False

        except Exception as e:
            logger.error(f"update prometheus rule:{rule_name} error => {e}")
            return False

        logger.info(f"update prometheus rule:{rule_name} success")
        return True


    def delete_prometheusrule(self, name):
        try:
            url = self.k8s_url + f"/apis/monitoring.coreos.com/v1/namespaces/{self.k8s_namespace}/prometheusrules/{name}"
            req = requests.delete(url=url, headers=self.k8s_header, verify=False)
            if req.status_code != 200:
                logger.error(f"delete prometheus rule:{name} failed => {req.text}")
                return False

        except Exception as e:
            logger.error(f"delete prometheus rule:{name} error => {e}")
            return False

        logger.info(f"delete prometheus rule:{name} success")
        return True



    # def convert_rule_data(self, db: Session, alarm_set_info: dict):
    #     rule_data={
    #         "apiVersion": 'monitoring.coreos.com/v1',
    #         "kind": 'PrometheusRule',
    #         "metadata":{
    #              "labels":{
    #                  "app.kubernetes.io/component": "alert-router",
    #                  "app.kubernetes.io/name": "alertmanager",
    #                  "app.kubernetes.io/part-of": "kube-prometheus",
    #                  "app.kubernetes.io/version": "0.21.0",
    #                  "prometheus": "k8s",
    #                  "role": "alert-rules"
    #              },
    #           "name": alarm_set_info["name"],
    #           "namespace": self.k8s_namespace,
    #         },
    #         "spec": {
    #             "groups":[]
    #         }
    #     }
    #     for alarm_group_info in alarm_set_info["alarm_groups"]:
    #         alarm_group = {
    #             "name": alarm_group_info["name"],
    #             "rules": []
    #         }
    #         for alarm_rule_info in alarm_group_info["alarm_rules"]:
    #             if not strtobool(str(alarm_rule_info["state"])):
    #                 continue

    #             expr = PromAlarmMetrics.convert_expr(db, alarm_rule_info["alarm_metrics_uuid"], alarm_rule_info["alarm_metrics_parm"])
    #             if alarm_rule_info["type"] == "alarm":
    #                 expr = expr + alarm_rule_info["operator"] + alarm_rule_info["value"]
    #                 alarm_rule= {
    #                     "alert": alarm_rule_info["name"],
    #                     "expr": expr,
    #                     "for": str(alarm_rule_info["duration"]) + "m",
    #                     "labels": alarm_rule_info["labels"],
    #                     "annotations": alarm_rule_info["annotations"],
    #                 }
    #             else:
    #                 alarm_rule= {
    #                     "record": alarm_rule_info["name"],
    #                     "expr": expr
    #                 }
    #             alarm_group["rules"].append(alarm_rule)

    #         rule_data["spec"]["groups"].append(alarm_group)


    #     return rule_data



    def query_prometheus_data(self, expression):
        try:
            url = f"{self.prometheus_url}api/v1/query?query={expression}"
            req = requests.get(url=url)
            if req.status_code != 200:
                logger.error(f"query prometheus expression:{expression} failed => {req.text}")
                return False

        except Exception as e:
            logger.error(f"query prometheus expression:{expression} error => {e}")
            return False

        logger.info(f"query prometheus expression:{expression} success")
        return req.json()['data']['result']



    def query_range_prometheus_data(self, expression, start, end, step=None):
        try:
            if not step:
                days = (end - start) / 60 / 60 / 24
                if days >= 7:
                    step = '4h'
                elif days >= 3:
                    step = '1h'
                elif days >= 1:
                    step = '15m'
                else:
                    step = '5m'
            url = f"{self.prometheus_url}api/v1/query_range?query={expression}&start={start}&end={end}&step={step}"
            req = requests.get(url=url)
            if req.status_code != 200:
                logger.error(f"query range prometheus expression:{expression} failed => {req.text}")
                return False, None

        except Exception as e:
            logger.error(f"query range prometheus expression:{expression} error => {e}")
            return False, None

        logger.info(f"query range prometheus expression:{expression} success")
        return True, req.json()['data']['result']


    def handle_values_to_float(self, values):
        data = []
        for value in values:
            value[1] = round(float(value[1]), 2)
            data.append(value[1])

        return data

    def handle_values_100_to_float(self, values):
        data = []
        for value in values:
            value[1] = round(float(value[1])*100, 2)
            data.append(value[1])

        return data


    def handle_values_to_int(self, values):
        data = []
        for value in values:
            value[1] = int(value[1])
            data.append(value[1])

        return data


def main():
    k8s_prometheus = K8sPrometheus()
    #avg(PrometheusRecordPodCpuUsage{container="event-processing"})by(container)
    #avg(PrometheusRecordPodMemUsage{container="agreement"})by(container)
    #avg(PrometheusRecordECSHostCpuUsage{i_host_name=~"airflow-pro01|airflow-pro02"})
    #avg(PrometheusRecordECSHostMemUsage{i_host_name=~"airflow-pro01|airflow-pro02"})
    # avg_expression = "avg(avg_over_time(PrometheusRecordPodCpuUsage{container='agreement', namespace='prod'}[1d] offset 1d)) by(container, namespace) * 100"
    # max_expression = "max(max_over_time(PrometheusRecordPodCpuUsage{container='agreement', namespace='prod'}[1d] offset 1d)) by(container, namespace) * 100"
    # min_expression = "min(min_over_time(PrometheusRecordPodCpuUsage{container='agreement', namespace='prod'}[1d] offset 1d)) by(container, namespace) * 100"
    # avg_prometheus_data = k8s_prometheus.query_prometheus_data(avg_expression)
    # max_prometheus_data = k8s_prometheus.query_prometheus_data(max_expression)
    # min_prometheus_data = k8s_prometheus.query_prometheus_data(min_expression)
    # print(avg_prometheus_data)
    # print(max_prometheus_data)
    # print(min_prometheus_data)
    # cpu_spec_expr = "count(node_cpu_seconds_total{i_host_name='aws-scan-test', job='node-exporter', mode='idle'})"
    # cpu_spec_data = k8s_prometheus.query_prometheus_data(cpu_spec_expr)
    # print(cpu_spec_data)

    #
    datetime_info = datetime.now() - timedelta(days=1)
    start_timestamp = datetime_info.replace(hour=0, minute=0, second=0, microsecond=0).timestamp()
    end_timestamp = datetime_info.replace(hour=23, minute=59, second=59, microsecond=0).timestamp()

    server_name = "biz-server"
    namespace = "prod"
    livability_expr = "kube_statefulset_status_replicas_ready{job='kube-state-metrics'," \
                      + f"statefulset='{server_name}'," + f"namespace='{namespace}'" \
                      + "} == 0"

    expr = 'sum(probe_success{instance=~"192.168.36.228:8080|192.168.36.229:8080"})'
    # expr = 'probe_success{instance="192.168.36.228:8080"}'
    pods_cpu_usage_data = k8s_prometheus.query_range_prometheus_data(expr, start_timestamp,end_timestamp)
    result = {
        pod_cpu_usage_data["metric"]["pod"]: [float(value[1]) for value in pod_cpu_usage_data["values"]]
        for pod_cpu_usage_data in pods_cpu_usage_data
    }
    # pd_data = {}
    # host_name1 = "airflow-pro01"
    # cpu_usage_expr1 = "PrometheusRecordECSHostCpuUsage{" + f"i_host_name='{host_name1}'" + "}"
    # cpu_usage_data1 = k8s_prometheus.query_range_prometheus_data(cpu_usage_expr1, start_timestamp, end_timestamp)
    # pd_data[host_name1] = [ float(value[1]) for value in cpu_usage_data1[0]["values"]]
    #
    # host_name2 = "airflow-pro02"
    # cpu_usage_expr2 = "PrometheusRecordECSHostCpuUsage{" + f"i_host_name='{host_name2}'" + "}"
    # cpu_usage_data2 = k8s_prometheus.query_range_prometheus_data(cpu_usage_expr2, start_timestamp, end_timestamp)
    # pd_data[host_name2] = [ float(value[1]) for value in cpu_usage_data2[0]["values"]]
    #
    # import pandas as pd
    # import numpy as np
    # print(pd_data)
    # df = pd.DataFrame.from_dict(pd_data, orient="columns")
    # print(df)
    # quantile_data = df.quantile(q=0.5)
    # print(quantile_data)
    # quantile_data = quantile_data.to_dict()
    #
    # # prometheus_data = k8s_prometheus.query_range_prometheus_data(expression, start_timestamp, end_timestamp)
    # print(quantile_data)

if __name__ == "__main__":
    main()

    #
    # def get_servicemonitor(self,namespace,name):
    #     url = self.k8s_url + "/apis/monitoring.coreos.com/v1/namespaces/{namespace}/servicemonitors/{name}".format(
    #         namespace=namespace, name=name)
    #     req = requests.get(url=url, headers=self.k8s_header, verify=False)
    #     print(req)
    #     return req
    #
    #
    #
    # def create_servicemonitor(self,namespace,data):
    #     url = self.k8s_url + "/apis/monitoring.coreos.com/v1/namespaces/{namespace}/servicemonitors/".format(
    #         namespace=namespace)
    #     req = requests.post(url=url, headers=self.k8s_header, verify=False, data=data)
    #     return req
    #
    #
    # def update_servicemonitor(self,namespace,name,data):
    #     url = self.k8s_url + "/apis/monitoring.coreos.com/v1/namespaces/{namespace}/servicemonitors/{name}".format(
    #         namespace=namespace, name=name)
    #     req = requests.put(url=url, data=data, headers=self.k8s_header, verify=False)
    #     return req
    #
    #
    # def delete_servicemonitor(self,namespace,name):
    #     url = self.k8s_url + "/apis/monitoring.coreos.com/v1/namespaces/{namespace}/servicemonitors/{name}".format(
    #         namespace=namespace, name=name)
    #     print(url)
    #     req = requests.delete(url=url, headers=self.k8s_header, verify=False)
    #     return req



